/*
 * DevicesSPIFlash.c
 *      Author: Honrun
 */
#include "gd32f30x.h"
#include "taskSystem.h"
#include "DevicesDelay.h"
#include "DevicesSPI.h"
#include "DevicesSPIFlash.h"


static uint32_t st_uiSPIFlashManufacturerID = 0;


void vSPIFlashInit(void)
{
    vSPI0Init();

    SPI_FLASH_CS_ENABLE();
    ucSPIxWriteReadByte(RESET_ENABLE_CMD);
    SPI_FLASH_CS_DISABLE();

    SPI_FLASH_CS_ENABLE();
    ucSPIxWriteReadByte(RESET_MEMORY_CMD);
    SPI_FLASH_CS_DISABLE();

    vDelayMs(50);
    st_uiSPIFlashManufacturerID = uiSPIFlashReadID();
}

static int8_t cSPIFlashLock(void)
{
//    xSemaphoreTakeRecursive(g_xSpiFlashSemaphore, portMAX_DELAY);

    return 0;
}

static int8_t cSPIFlashUnlock(void)
{
//    xSemaphoreGiveRecursive(g_xSpiFlashSemaphore);

    return 0;
}

static uint8_t ucSPIFlashReadStatus(uint32_t uiFlag)
{
    uint32_t uiTimeout = 20000;
    uint8_t ucStatus;

//    /* 判断 SPI Flash 是否连接正常 */
//    if((st_uiSPIFlashManufacturerID & 0xFF) != Manufacturer_ID_GD25Q32E)
//        return uiFlag;

    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(READ_STATUS_REG_CMD);

    /* 等待Flash状态 */
    while(--uiTimeout)
    {
        ucStatus = ucSPIxWriteReadByte(0xFF);

        if((ucStatus & uiFlag) != uiFlag)
            break;

        vDelayUs(10);
    }

    SPI_FLASH_CS_DISABLE();

    return (ucStatus & uiFlag);
}

static void uvSPIFlashEnableWrite(void)
{
    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(WRITE_ENABLE_CMD);

    SPI_FLASH_CS_DISABLE();
}

int8_t cSPIFlashErases(uint32_t uiAddress)
{
    uint8_t ucAddress[3] = {uiAddress >> 16, uiAddress >> 8, uiAddress};
    int8_t cError = 0;

    cSPIFlashLock();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
    {
        cError = 1;
        goto __EXIT;
    }

    uvSPIFlashEnableWrite();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
    {
        cError = 2;
        goto __EXIT;
    }

    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(SUBSECTOR_ERASE_CMD);
    cError |= cSPIxWriteDatas(ucAddress, 3);

    SPI_FLASH_CS_DISABLE();

__EXIT:
    cSPIFlashUnlock();

    return cError;
}

static int8_t cSPIFlashWritePage(uint32_t uiAddress, uint8_t *pucDatas, int32_t iLength)
{
    uint8_t ucAddress[3] = {uiAddress >> 16, uiAddress >> 8, uiAddress};
    int8_t cError = 0;

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return 1;

    uvSPIFlashEnableWrite();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return 2;

    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(PAGE_PROG_CMD);
    cError |= cSPIxWriteDatas(ucAddress, 3);

    /* 写入数据 */
    cError |= cSPIxWriteDatas(pucDatas, iLength);

    SPI_FLASH_CS_DISABLE();

    return cError;
}

int8_t cSPIFlashNoErasesWriteDatas(uint32_t uiAddress, const void *pvBuff, int32_t iLength)
{
    int32_t iLengthTemp = 0;
    uint8_t *pucDatas = (uint8_t *)pvBuff;
    int8_t cError = 0;

    cSPIFlashLock();

    /* Write Flash */
    while(iLength > 0)
    {
        /* 页对齐 */
        iLengthTemp = (iLength > (SPI_FLASH_PAGE_SIZE - (uiAddress % SPI_FLASH_PAGE_SIZE))) ? (SPI_FLASH_PAGE_SIZE - (uiAddress % SPI_FLASH_PAGE_SIZE)) : iLength;

        if(cSPIFlashWritePage(uiAddress, pucDatas, iLengthTemp) != 0)
        {
            cError |= 2;
            break;
        }

        uiAddress += iLengthTemp;
        iLength -= iLengthTemp;
        pucDatas += iLengthTemp;
    }

    cSPIFlashUnlock();

    return cError;
}

int8_t cSPIFlashWriteDatas(uint32_t uiAddress, const void *pvBuff, int32_t iLength)
{
    int32_t iLengthTemp = 0;
    uint8_t *pucDatas = (uint8_t *)pvBuff;
    int8_t cError = 0;

    cSPIFlashLock();

    /* Write Flash */
    while(iLength > 0)
    {
        /* 块起始地址时，需要先擦除该页 */
        if((uiAddress % SPI_FLASH_BLOCK_SIZE) == 0)
        {
            if(cSPIFlashErases(uiAddress) != 0)
            {
                cError |= 1;
                break;
            }
        }

        /* 页对齐 */
        iLengthTemp = (iLength > (SPI_FLASH_PAGE_SIZE - (uiAddress % SPI_FLASH_PAGE_SIZE))) ? (SPI_FLASH_PAGE_SIZE - (uiAddress % SPI_FLASH_PAGE_SIZE)) : iLength;

        if(cSPIFlashWritePage(uiAddress, pucDatas, iLengthTemp) != 0)
        {
            cError |= 2;
            break;
        }

        uiAddress += iLengthTemp;
        iLength -= iLengthTemp;
        pucDatas += iLengthTemp;
    }

    cSPIFlashUnlock();

    return cError;
}

int8_t cSPIFlashReadDatas(uint32_t uiAddress, void *pvBuff, int32_t iLength)
{
    uint8_t ucAddress[3] = {uiAddress >> 16, uiAddress >> 8, uiAddress};
    int8_t cError;

    cSPIFlashLock();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
    {
        cError = 1;
        goto __EXIT;
    }

    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(READ_CMD);
    cError = cSPIxWriteDatas(ucAddress, 3);

    /* 读取数据 */
    cError |= cSPIxReadDatas(pvBuff, iLength);

    SPI_FLASH_CS_DISABLE();

__EXIT:
    cSPIFlashUnlock();

    return cError;
}

uint32_t uiSPIFlashReadID(void)
{
    uint32_t uiID;

    cSPIFlashLock();

    SPI_FLASH_CS_ENABLE();

    ucSPIxWriteReadByte(READ_ID_CMD2);
    cSPIxReadDatas(&uiID, 3);

    SPI_FLASH_CS_DISABLE();

    cSPIFlashUnlock();

    return uiID;
}
